home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 February (DVD) / PCWorld_2008-02_DVD.iso / v cisle / PHP / PHP.exe / xampp-win32-1.6.5-installer.exe / php / PEAR / Net / DIME.php < prev    next >
Encoding:
PHP Script  |  2007-12-20  |  21.8 KB  |  629 lines

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2002 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Shane Caraveo <shane@caraveo.com>                           |
  17. // |           Ralf Hofmann <ralf.hofmann@verdisoft.com>                      |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: DIME.php,v 1.5 2002/09/29 01:55:16 shane Exp $
  21. //
  22.  
  23. require_once 'PEAR.php';
  24. /**
  25.  *
  26.  *  DIME Encoding/Decoding
  27.  *
  28.  * What is it?
  29.  *   This class enables you to manipulate and build
  30.  *   a DIME encapsulated message.
  31.  *
  32.  * http://www.ietf.org/internet-drafts/draft-nielsen-dime-02.txt
  33.  *
  34.  * 09/18/02 Ralf -  A huge number of changes to be compliant 
  35.  *                     with the DIME Specification Release 17 June 2002
  36.  * 
  37.  * TODO: lots of stuff needs to be tested.
  38.  *           Definitily have to go through DIME spec and
  39.  *           make things work right, most importantly, sec 3.3
  40.  *           make examples, document
  41.  *
  42.  * see test/dime_mesage_test.php for example of usage
  43.  * 
  44.  * @author  Shane Caraveo <shane@caraveo.com>, 
  45.  *          Ralf Hofmann <ralf.hofmann@verdisoft.com>     
  46.  * @version $Revision: 1.5 $
  47.  * @package Net_DIME
  48.  */
  49. define('NET_DIME_TYPE_UNCHANGED',0x00);
  50. define('NET_DIME_TYPE_MEDIA',0x01);
  51. define('NET_DIME_TYPE_URI',0x02);
  52. define('NET_DIME_TYPE_UNKNOWN',0x03);
  53. define('NET_DIME_TYPE_NONE',0x04);
  54.  
  55. define('NET_DIME_VERSION',0x0001);
  56.  
  57. define('NET_DIME_RECORD_HEADER',12);
  58.  
  59. define('NET_DIME_FLAGS', 0);
  60. define('NET_DIME_OPTS_LEN', 1);
  61. define('NET_DIME_ID_LEN', 2);
  62. define('NET_DIME_TYPE_LEN', 3);
  63. define('NET_DIME_DATA_LEN', 4);
  64. define('NET_DIME_OPTS', 5);
  65. define('NET_DIME_ID', 6);
  66. define('NET_DIME_TYPE', 7);
  67. define('NET_DIME_DATA', 8);
  68.  
  69. class Net_DIME_Record extends PEAR
  70. {
  71.     // these are used to hold the padded length
  72.     var $OPTS_LENGTH = 0;
  73.     var $ID_LENGTH = 0;
  74.     var $TYPE_LENGTH = 0; 
  75.     var $DATA_LENGTH = 0;
  76.     var $_haveOpts = FALSE;
  77.     var $_haveID = FALSE;
  78.     var $_haveType = FALSE;
  79.     var $_haveData = FALSE;
  80.     var $debug = FALSE;
  81.     var $padstr = "\0";
  82.     /**
  83.      * Elements
  84.      * [NET_DIME_FLAGS],    16 bits: VERSION:MB:ME:CF:TYPE_T
  85.      * [NET_DIME_OPTS_LEN], 16 bits: OPTIONS_LENGTH
  86.      * [NET_DIME_ID_LEN],   16 bits: ID_LENGTH
  87.      * [NET_DIME_TYPE_LEN], 16 bits: TYPE_LENGTH
  88.      * [NET_DIME_DATA_LEN], 32 bits: DATA_LENGTH
  89.      * [NET_DIME_OPTS]             : OPTIONS
  90.      * [NET_DIME_ID]                : ID
  91.      * [NET_DIME_TYPE]             : TYPE
  92.      * [NET_DIME_DATA]             : DATA
  93.      */
  94.     var $Elements = array(NET_DIME_FLAGS => 0,  NET_DIME_OPTS_LEN => 0, 
  95.                           NET_DIME_ID_LEN => 0, NET_DIME_TYPE_LEN => 0, 
  96.                            NET_DIME_DATA_LEN => 0,
  97.                            NET_DIME_OPTS => '',
  98.                           NET_DIME_ID => '',
  99.                           NET_DIME_TYPE => '',
  100.                           NET_DIME_DATA => '');
  101.     
  102.     function Net_DIME_Record($debug = FALSE)
  103.     {
  104.         $this->debug = $debug;
  105.         if ($debug) $this->padstr = '*';
  106.     }
  107.  
  108.     function setMB()
  109.     {
  110.         $this->Elements[NET_DIME_FLAGS] |= 0x0400;
  111.     }
  112.  
  113.     function setME()
  114.     {
  115.         $this->Elements[NET_DIME_FLAGS] |= 0x0200;
  116.     }
  117.  
  118.     function setCF()
  119.     {
  120.         $this->Elements[NET_DIME_FLAGS] |= 0x0100;
  121.     }
  122.  
  123.     function isChunk()
  124.     {
  125.         return $this->Elements[NET_DIME_FLAGS] & 0x0100;
  126.     }
  127.  
  128.     function isEnd()
  129.     {
  130.         return $this->Elements[NET_DIME_FLAGS] & 0x0200;
  131.     }
  132.     
  133.     function isStart()
  134.     {
  135.         return $this->Elements[NET_DIME_FLAGS] & 0x0400;
  136.     }
  137.     
  138.     function getID()
  139.     {
  140.         return $this->Elements[NET_DIME_ID];
  141.     }
  142.  
  143.     function getType()
  144.     {
  145.         return $this->Elements[NET_DIME_TYPE];
  146.     }
  147.  
  148.     function getData()
  149.     {
  150.         return $this->Elements[NET_DIME_DATA];
  151.     }
  152.     
  153.     function getDataLength()
  154.     {
  155.         return $this->Elements[NET_DIME_DATA_LEN];
  156.     }
  157.     
  158.     function setType($typestring, $type=NET_DIME_TYPE_UNKNOWN)
  159.     {
  160.         $typelen = strlen($typestring) & 0xFFFF;
  161.         $type = $type << 4;
  162.         $this->Elements[NET_DIME_FLAGS] = ($this->Elements[NET_DIME_FLAGS] & 0xFF0F) | $type;
  163.         $this->Elements[NET_DIME_TYPE_LEN] = $typelen;
  164.         $this->TYPE_LENGTH = $this->_getPadLength($typelen);
  165.         $this->Elements[NET_DIME_TYPE] = $typestring;
  166.     }
  167.     
  168.     function generateID()
  169.     {
  170.         $id = md5(time());
  171.         $this->setID($id);
  172.         return $id;
  173.     }
  174.     
  175.     function setID($id)
  176.     {
  177.         $idlen = strlen($id) & 0xFFFF;
  178.         $this->Elements[NET_DIME_ID_LEN] = $idlen;
  179.         $this->ID_LENGTH = $this->_getPadLength($idlen);
  180.         $this->Elements[NET_DIME_ID] = $id;
  181.     }
  182.     
  183.     function setData($data, $size=0)
  184.     {
  185.         $datalen = $size?$size:strlen($data);
  186.         $this->Elements[NET_DIME_DATA_LEN] = $datalen;
  187.         $this->DATA_LENGTH = $this->_getPadLength($datalen);
  188.         $this->Elements[NET_DIME_DATA] = $data;
  189.     }
  190.     
  191.     function encode()
  192.     {
  193.         // insert version 
  194.         $this->Elements[NET_DIME_FLAGS] = ($this->Elements[NET_DIME_FLAGS] & 0x07FF) | (NET_DIME_VERSION << 11);
  195.  
  196.         // the real dime encoding
  197.         $format =   '%c%c%c%c%c%c%c%c%c%c%c%c'.
  198.                     '%'.$this->OPTS_LENGTH.'s'.
  199.                     '%'.$this->ID_LENGTH.'s'.
  200.                     '%'.$this->TYPE_LENGTH.'s'.
  201.                     '%'.$this->DATA_LENGTH.'s';
  202.         return sprintf($format,
  203.                        ($this->Elements[NET_DIME_FLAGS]&0x0000FF00)>>8,
  204.                        ($this->Elements[NET_DIME_FLAGS]&0x000000FF),
  205.                        ($this->Elements[NET_DIME_OPTS_LEN]&0x0000FF00)>>8,
  206.                        ($this->Elements[NET_DIME_OPTS_LEN]&0x000000FF),
  207.                        ($this->Elements[NET_DIME_ID_LEN]&0x0000FF00)>>8,
  208.                        ($this->Elements[NET_DIME_ID_LEN]&0x000000FF),
  209.                        ($this->Elements[NET_DIME_TYPE_LEN]&0x0000FF00)>>8,
  210.                        ($this->Elements[NET_DIME_TYPE_LEN]&0x000000FF),
  211.                        ($this->Elements[NET_DIME_DATA_LEN]&0xFF000000)>>24,
  212.                        ($this->Elements[NET_DIME_DATA_LEN]&0x00FF0000)>>16,
  213.                        ($this->Elements[NET_DIME_DATA_LEN]&0x0000FF00)>>8,
  214.                        ($this->Elements[NET_DIME_DATA_LEN]&0x000000FF),
  215.                        str_pad($this->Elements[NET_DIME_OPTS], $this->OPTS_LENGTH, $this->padstr),
  216.                        str_pad($this->Elements[NET_DIME_ID], $this->ID_LENGTH, $this->padstr),
  217.                        str_pad($this->Elements[NET_DIME_TYPE], $this->TYPE_LENGTH, $this->padstr),
  218.                        str_pad($this->Elements[NET_DIME_DATA], $this->DATA_LENGTH, $this->padstr));
  219.     }
  220.     
  221.     function _getPadLength($len)
  222.     {
  223.         $pad = 0;
  224.         if ($len) {
  225.             $pad = $len % 4;
  226.             if ($pad) $pad = 4 - $pad;
  227.         }
  228.         return $len + $pad;
  229.     }
  230.     
  231.     function decode(&$data)
  232.     {
  233.         // REAL DIME decoding
  234.         $this->Elements[NET_DIME_FLAGS]    = (hexdec(bin2hex($data[0]))<<8) + hexdec(bin2hex($data[1]));
  235.         $this->Elements[NET_DIME_OPTS_LEN] = (hexdec(bin2hex($data[2]))<<8) + hexdec(bin2hex($data[3]));
  236.         $this->Elements[NET_DIME_ID_LEN]   = (hexdec(bin2hex($data[4]))<<8) + hexdec(bin2hex($data[5]));
  237.         $this->Elements[NET_DIME_TYPE_LEN] = (hexdec(bin2hex($data[6]))<<8) + hexdec(bin2hex($data[7]));
  238.         $this->Elements[NET_DIME_DATA_LEN] = (hexdec(bin2hex($data[8]))<<24) +
  239.                                      (hexdec(bin2hex($data[9]))<<16) +
  240.                                      (hexdec(bin2hex($data[10]))<<8) +
  241.                                       hexdec(bin2hex($data[11]));
  242.         $p = 12;
  243.         
  244.         $version = (($this->Elements[NET_DIME_FLAGS]>>11) & 0x001F);
  245.         
  246.         if ($version == NET_DIME_VERSION) 
  247.         {
  248.             $this->OPTS_LENGTH = $this->_getPadLength($this->Elements[NET_DIME_OPTS_LEN]);        
  249.             $this->ID_LENGTH = $this->_getPadLength($this->Elements[NET_DIME_ID_LEN]);
  250.             $this->TYPE_LENGTH = $this->_getPadLength($this->Elements[NET_DIME_TYPE_LEN]);
  251.             $this->DATA_LENGTH = $this->_getPadLength($this->Elements[NET_DIME_DATA_LEN]);
  252.                     
  253.             $datalen = strlen($data);
  254.             $this->Elements[NET_DIME_OPTS] = substr($data,$p,$this->Elements[NET_DIME_OPTS_LEN]);
  255.             $this->_haveOpts = (strlen($this->Elements[NET_DIME_OPTS]) == $this->Elements[NET_DIME_OPTS_LEN]);
  256.             if ($this->_haveOpts) {
  257.                 $p += $this->OPTS_LENGTH;        
  258.                 $this->Elements[NET_DIME_ID] = substr($data,$p,$this->Elements[NET_DIME_ID_LEN]);
  259.                 $this->_haveID = (strlen($this->Elements[NET_DIME_ID]) == $this->Elements[NET_DIME_ID_LEN]);
  260.                 if ($this->_haveID) {
  261.                     $p += $this->ID_LENGTH;
  262.                     $this->Elements[NET_DIME_TYPE] = substr($data,$p,$this->Elements[NET_DIME_TYPE_LEN]);
  263.                     $this->_haveType = (strlen($this->Elements[NET_DIME_TYPE]) == $this->Elements[NET_DIME_TYPE_LEN]);
  264.                     if ($this->_haveType) {
  265.                         $p += $this->TYPE_LENGTH;
  266.                         $this->Elements[NET_DIME_DATA] = substr($data,$p,$this->Elements[NET_DIME_DATA_LEN]);
  267.                         $this->_haveData = (strlen($this->Elements[NET_DIME_DATA]) == $this->Elements[NET_DIME_DATA_LEN]);
  268.                         if ($this->_haveData) {
  269.                             $p += $this->DATA_LENGTH;
  270.                         } else {
  271.                             $p += strlen($this->Elements[NET_DIME_DATA]);
  272.                         }
  273.                     } else {
  274.                         $p += strlen($this->Elements[NET_DIME_TYPE]);
  275.                     }
  276.                 } else {
  277.                     $p += strlen($this->Elements[NET_DIME_ID]);
  278.                 }
  279.             } else {
  280.                 $p += strlen($this->Elements[NET_DIME_OPTS]);                    
  281.             }
  282.         }
  283.         return substr($data, $p);
  284.     }
  285.     
  286.     function addData(&$data)
  287.     {
  288.         $datalen = strlen($data);
  289.         $p = 0;
  290.         if (!$this->_haveOpts) {
  291.             $have = strlen($this->Elements[NET_DIME_OPTS]);
  292.             $this->Elements[NET_DIME_OPTS] .= substr($data,$p,$this->Elements[NET_DIME_OPTS_LEN]-$have);
  293.             $this->_haveOpts = (strlen($this->Elements[NET_DIME_OPTS]) == $this->Elements[DIME_OTPS_LEN]);
  294.             if (!$this->_haveOpts) return NULL;
  295.             $p += $this->OPTS_LENGTH-$have;
  296.         }
  297.         if (!$this->_haveID) {
  298.             $have = strlen($this->Elements[NET_DIME_ID]);
  299.             $this->Elements[NET_DIME_ID] .= substr($data,$p,$this->Elements[NET_DIME_ID_LEN]-$have);
  300.             $this->_haveID = (strlen($this->Elements[NET_DIME_ID]) == $this->Elements[NET_DIME_ID_LEN]);
  301.             if (!$this->_haveID) return NULL;
  302.             $p += $this->ID_LENGTH-$have;
  303.         }
  304.         if (!$this->_haveType && $p < $datalen) {
  305.             $have = strlen($this->Elements[NET_DIME_TYPE]);
  306.             $this->Elements[NET_DIME_TYPE] .= substr($data,$p,$this->Elements[NET_DIME_TYPE_LEN]-$have);
  307.             $this->_haveType = (strlen($this->Elements[NET_DIME_TYPE]) == $this->Elements[NET_DIME_TYPE_LEN]);
  308.             if (!$this->_haveType) return NULL;
  309.             $p += $this->TYPE_LENGTH-$have;
  310.         }
  311.         if (!$this->_haveData && $p < $datalen) {
  312.             $have = strlen($this->Elements[NET_DIME_DATA]);
  313.             $this->Elements[NET_DIME_DATA] .= substr($data,$p,$this->Elements[NET_DIME_DATA_LEN]-$have);
  314.             $this->_haveData = (strlen($this->Elements[NET_DIME_DATA]) == $this->Elements[NET_DIME_DATA_LEN]);
  315.             if (!$this->_haveData) return NULL;
  316.             $p += $this->DATA_LENGTH-$have;
  317.         }
  318.         return substr($data,$p);
  319.     }   
  320. }
  321.  
  322.  
  323. class Net_DIME_Message extends PEAR
  324. {
  325.  
  326.     var $record_size = 4096;
  327.     #var $records =array();
  328.     var $parts = array();
  329.     var $currentPart = -1;
  330.     var $stream = NULL;
  331.     var $_currentRecord;
  332.     var $_proc = array();
  333.     var $type;
  334.     var $typestr;
  335.     var $mb = 1;
  336.     var $me = 0;
  337.     var $cf = 0;
  338.     var $id = NULL;
  339.     var $debug = FALSE;
  340.     /**
  341.      * constructor
  342.      *
  343.      * this currently takes a file pointer as provided
  344.      * by fopen
  345.      *
  346.      * TODO: integrate with the php streams stuff
  347.      */
  348.     function Net_DIME_Message($stream=NULL, $record_size = 4096, $debug = FALSE)
  349.     {
  350.         $this->stream = $stream;
  351.         $this->record_size = $record_size;
  352.         $this->debug = $debug;
  353.     }
  354.     
  355.     function _makeRecord(&$data, $typestr='', $id=NULL, $type=NET_DIME_TYPE_UNKNOWN)
  356.     {
  357.         $record = new Net_DIME_Record($this->debug);
  358.         if ($this->mb) {
  359.             $record->setMB();
  360.             // all subsequent records are not message begin!
  361.             $this->mb = 0; 
  362.         }
  363.         if ($this->me) $record->setME();
  364.         if ($this->cf) $record->setCF();
  365.         $record->setData($data);
  366.         $record->setType($typestr,$type);
  367.         if ($id) $record->setID($id);
  368.         #if ($this->debug) {
  369.         #    print str_replace('\0','*',$record->encode());
  370.         #}
  371.         return $record->encode();
  372.     }
  373.     
  374.     function startChunk(&$data, $typestr='', $id=NULL, $type=NET_DIME_TYPE_UNKNOWN)
  375.     {
  376.         $this->me = 0;
  377.         $this->cf = 1;
  378.         $this->type = $type;
  379.         $this->typestr = $typestr;
  380.         if ($id) {
  381.             $this->id = $id;
  382.         } else {
  383.             $this->id = md5(time());
  384.         }
  385.         return $this->_makeRecord($data, $this->typestr, $this->id, $this->type);
  386.     }
  387.  
  388.     function doChunk(&$data)
  389.     {
  390.         $this->me = 0;
  391.         $this->cf = 1;
  392.         return $this->_makeRecord($data, NULL, NULL, NET_DIME_TYPE_UNCHANGED);
  393.     }
  394.  
  395.     function endChunk()
  396.     {
  397.         $this->cf = 0;
  398.         $data = NULL;
  399.         $rec = $this->_makeRecord($data, NULL, NULL, NET_DIME_TYPE_UNCHANGED);
  400.         $this->id = 0;
  401.         $this->cf = 0;
  402.         $this->id = 0;
  403.         $this->type = NET_DIME_TYPE_UNKNOWN;
  404.         $this->typestr = NULL;
  405.         return $rec;
  406.     }
  407.     
  408.     function endMessage()
  409.     {
  410.         $this->me = 1;
  411.         $data = NULL;
  412.         $rec = $this->_makeRecord($data, NULL, NULL, NET_DIME_TYPE_NONE);
  413.         $this->me = 0;
  414.         $this->mb = 1;
  415.         $this->id = 0;
  416.         return $rec;
  417.     }
  418.     
  419.     /**
  420.      * sendRecord
  421.      *
  422.      * given a chunk of data, it creates DIME records
  423.      * and writes them to the stream
  424.      *
  425.      */
  426.     function sendData(&$data, $typestr='', $id=NULL, $type=NET_DIME_TYPE_UNKNOWN)
  427.     {
  428.         $len = strlen($data);
  429.         if ($len > $this->record_size) {
  430.             $chunk = substr($data, 0, $this->record_size);
  431.             $p = $this->record_size;
  432.             $rec = $this->startChunk($chunk,$typestr,$id,$type);
  433.             fwrite($this->stream, $rec);
  434.             while ($p < $len) {
  435.                 $chunk = substr($data, $p, $this->record_size);
  436.                 $p += $this->record_size;
  437.                 $rec = $this->doChunk($chunk);
  438.                 fwrite($this->stream, $rec);
  439.             }
  440.             $rec = $this->endChunk();
  441.             fwrite($this->stream, $rec);
  442.             return;
  443.         }
  444.         $rec = $this->_makeRecord($data, $typestr,$id,$type);
  445.         fwrite($this->stream, $rec);
  446.     }
  447.     
  448.     function sendEndMessage()
  449.     {
  450.         $rec = $this->endMessage();
  451.         fwrite($this->stream, $rec);
  452.     }
  453.     
  454.     /**
  455.      * sendFile
  456.      *
  457.      * given a filename, it reads the file,
  458.      * creates records and writes them to the stream
  459.      *
  460.      */
  461.     function sendFile($filename, $typestr='', $id=NULL, $type=NET_DIME_TYPE_UNKNOWN)
  462.     {
  463.         $f = fopen($filename, "rb");
  464.         if ($f) {
  465.             if ($data = fread($f, $this->record_size)) {
  466.                 $this->startChunk($data,$typestr,$id,$type);
  467.             }
  468.             while ($data = fread($f, $this->record_size)) {
  469.                 $this->doChunk($data,$typestr,$id,$type);
  470.             }
  471.             $this->endChunk();
  472.             fclose($f);
  473.         }
  474.     }
  475.  
  476.     /**
  477.      * encodeData
  478.      *
  479.      * given data, encode it in DIME
  480.      *
  481.      */
  482.     function encodeData($data, $typestr='', $id=NULL, $type=NET_DIME_TYPE_UNKNOWN)
  483.     {
  484.         $len = strlen($data);
  485.         $resp = '';
  486.         if ($len > $this->record_size) {
  487.             $chunk = substr($data, 0, $this->record_size);
  488.             $p = $this->record_size;
  489.             $resp .= $this->startChunk($chunk,$typestr,$id,$type);
  490.             while ($p < $len) {
  491.                 $chunk = substr($data, $p, $this->record_size);
  492.                 $p += $this->record_size;
  493.                 $resp .= $this->doChunk($chunk);
  494.             }
  495.             $resp .= $this->endChunk();
  496.         } else {
  497.             $resp .= $this->_makeRecord($data, $typestr,$id,$type);
  498.         }
  499.         return $resp;
  500.     }
  501.  
  502.     /**
  503.      * sendFile
  504.      *
  505.      * given a filename, it reads the file,
  506.      * creates records and writes them to the stream
  507.      *
  508.      */
  509.     function encodeFile($filename, $typestr='', $id=NULL, $type=NET_DIME_TYPE_UNKNOWN)
  510.     {
  511.         $f = fopen($filename, "rb");
  512.         if ($f) {
  513.             if ($data = fread($f, $this->record_size)) {
  514.                 $resp = $this->startChunk($data,$typestr,$id,$type);
  515.             }
  516.             while ($data = fread($f, $this->record_size)) {
  517.                 $resp = $this->doChunk($data,$typestr,$id,$type);
  518.             }
  519.             $resp = $this->endChunk();
  520.             fclose($f);
  521.         }
  522.         return $resp;
  523.     }
  524.     
  525.     /**
  526.      * _processData
  527.      *
  528.      * creates Net_DIME_Records from provided data
  529.      *
  530.      */
  531.     function _processData(&$data)
  532.     {
  533.         $leftover = NULL;
  534.         if (!$this->_currentRecord) {
  535.             $this->_currentRecord = new Net_DIME_Record($this->debug);
  536.             $data = $this->_currentRecord->decode($data);
  537.         } else {
  538.             $data = $this->_currentRecord->addData($data);
  539.         }
  540.                 
  541.         if ($this->_currentRecord->_haveData) {
  542.             if (count($this->parts)==0 && !$this->_currentRecord->isStart()) {
  543.                 // raise an error!
  544.                 return PEAR::raiseError('First Message is not a DIME begin record!');
  545.             }
  546.  
  547.             if ($this->_currentRecord->isEnd() && $this->_currentRecord->getDataLength()==0) {
  548.                 return NULL;
  549.             }
  550.             
  551.             if ($this->currentPart < 0 && !$this->_currentRecord->isChunk()) {
  552.                 $this->parts[] = array();
  553.                 $this->currentPart = count($this->parts)-1;
  554.                 $this->parts[$this->currentPart]['id']   = $this->_currentRecord->getID();
  555.                 $this->parts[$this->currentPart]['type'] = $this->_currentRecord->getType();
  556.                 $this->parts[$this->currentPart]['data'] = $this->_currentRecord->getData();
  557.                 $this->currentPart = -1;
  558.             } else {
  559.                 if ($this->currentPart < 0) {
  560.                     $this->parts[] = array();
  561.                     $this->currentPart = count($this->parts)-1;
  562.                     $this->parts[$this->currentPart]['id']   = $this->_currentRecord->getID();
  563.                     $this->parts[$this->currentPart]['type'] = $this->_currentRecord->getType();
  564.                     $this->parts[$this->currentPart]['data'] = $this->_currentRecord->getData();
  565.                 } else {
  566.                     $this->parts[$this->currentPart]['data'] .= $this->_currentRecord->getData();
  567.                     if (!$this->_currentRecord->isChunk()) {
  568.                         // we reached the end of the chunk
  569.                         $this->currentPart = -1;
  570.                     }
  571.                 }
  572.             }
  573.             #$this->records[] = $this->_currentRecord;
  574.             if (!$this->_currentRecord->isEnd()) $this->_currentRecord = NULL;
  575.         }
  576.         return NULL;
  577.     }
  578.     
  579.     /**
  580.      * decodeData
  581.      *
  582.      * decodes a DIME encrypted string of data
  583.      *
  584.      */
  585.     function decodeData(&$data) {
  586.         while (strlen($data) >= NET_DIME_RECORD_HEADER) {
  587.             $err = $this->_processData($data);
  588.             if (PEAR::isError($err)) {
  589.                 return $err;
  590.             }
  591.         }
  592.     }
  593.     
  594.     /**
  595.      * read
  596.      *
  597.      * reads the stream and creates
  598.      * an array of records
  599.      *
  600.      * it can accept the start of a previously read buffer
  601.      * this is usefull in situations where you need to read
  602.      * headers before discovering that the data is DIME encoded
  603.      * such as in the case of reading an HTTP response.
  604.      */
  605.     function read($buf=NULL)
  606.     {
  607.         while ($data = fread($this->stream, 8192)) {
  608.             if ($buf) {
  609.                 $data = $buf.$data;
  610.                 $buf = NULL;
  611.             }
  612.             if ($this->debug)
  613.                 echo "read: ".strlen($data)." bytes\n";
  614.             $err = $this->decodeData($data);
  615.             if (PEAR::isError($err)) {
  616.                 return $err;
  617.             }
  618.             
  619.             // store any leftover data to be used again
  620.             // should be < NET_DIME_RECORD_HEADER bytes
  621.             $buf = $data;
  622.         }
  623.         if (!$this->_currentRecord || !$this->_currentRecord->isEnd()) {
  624.             return PEAR::raiseError('reached stream end without end record');
  625.         }
  626.         return NULL;
  627.     }
  628. }
  629. ?>